package com.hamishmedlin.psxpw;

public class QDecoder {

	private static String unFormatPassword(String password){
		password = password.toLowerCase();
		password = password.trim();
		
		password = password.replace(" ", "");
		
		return password;
	}
	
	private static boolean validatePasswordBasic(String password){
		int i;
		
		if(password.length() != 10){
			return false;
		}
		
		for(i = 0; i < 10;i++){
			if(QGlobals.passwordChar.indexOf(password.charAt(i)) == -1){
				return false;
			}
		}
		
		for(i = 0; i < 10; i++){
			QGlobals.passwordData[i] = QGlobals.passwordChar.indexOf(password.charAt(i));
		}
		return true;
	}
	
	private static int decodePassItem(int bytecode,int maxvalue){
		int value;
		int bitsum = bytecode * maxvalue;
		
		if(bitsum >= 0){
			value = bitsum >> 3;
		}else{
			value = (bitsum +7) >> 3;
		}
		
		return value;
	}
	
	public static FormData decodePassword(String password) throws FailedDecode{
		
		password = unFormatPassword(password);
		if(!validatePasswordBasic(password)){
			throw new FailedDecode("Password is in an invalid format");
		}
		
		FormData fd = new FormData();
		
		int i;
		int[] temp = new int[10];
		
		for(i = 0; i < 10; i++){
			temp[i] = QGlobals.passwordData[i];
		}
		
		int encryptionKey = temp[9];
		int computedKey = 0;
		
		for(i = 0;i < 9;i++){
			temp[i] ^= encryptionKey;
			computedKey ^= temp[i];
		}
		
		if(computedKey != encryptionKey){
			throw new FailedDecode("Password does not hash!");
		}
		
		if((temp[8] & 28) != 0){
			throw new FailedDecode("Invalid password!");
		}
		
		int gamemap = (temp[0] << 1) | ((temp[1] & 16) >> 4);
		if(gamemap <= 0 || gamemap > 59){
			throw new FailedDecode("Invalid destination level!");
		}
		fd.setNextMap(gamemap);
		
		int skill = (temp[1] & 12) >> 2;
		if(skill < 0 || skill > 3){
			throw new FailedDecode("Invalid skill level!");
		}
		fd.setGameSkil(skill);
		
		
		int backpack = (temp[1] & 2) >> 1;
		fd.setChecked(QGlobals.BACKPACK, backpack != 0);
		
		fd.setChecked(QGlobals.WEAPON_CHAINSAW, (temp[1] & 1) != 0);
		fd.setChecked(QGlobals.WEAPON_BFG, (temp[2] & 16) != 0);
		fd.setChecked(QGlobals.WEAPON_PLASMA, (temp[2] & 8) != 0);
		fd.setChecked(QGlobals.WEAPON_ROCKET, (temp[2] & 4) != 0);
		fd.setChecked(QGlobals.WEAPON_CHAINGUN, (temp[2] & 2) != 0);
		fd.setChecked(QGlobals.WEAPON_SSG, (temp[2] & 1) != 0);
		fd.setChecked(QGlobals.WEAPON_SHOTGUN, (temp[3] & 16) != 0);		
		
		int[] ammoToUse = QGlobals.normMaxAmmo;
		if(backpack != 0){
			ammoToUse = QGlobals.backMaxAmmo;
		}
		
		int clip = temp[3] & 15;
		int shell = (temp[4] & 30) >> 1;
		int cell = ((temp[4] & 1) << 3) | ((temp[5] & 28) >> 2);
		int misl = ((temp[5] & 3) << 2) | ((temp[6] & 24) >> 3);
		
		fd.setClip(decodePassItem(clip, ammoToUse[0]));
		fd.setShell(decodePassItem(shell, ammoToUse[1]));
		fd.setRockets(decodePassItem(misl, ammoToUse[2]));
		fd.setCell(decodePassItem(cell, ammoToUse[3]));
		
		int health = ((temp[6] & 7) << 1) | ((temp[7] & 16) >> 4);
		int armor = temp[7] & 15;
		
		fd.setHealth(decodePassItem(health, 200));
		fd.setArmor(decodePassItem(armor, 200));
		
		int armorclass = temp[8] & 3;
		
		fd.setArmorType(armorclass);
		
		return fd;
	}
}
